/*****************************************************\
* Copyright (c) 2019 The Agile Authors. All rights reserved.
  Use of this source code is governed by a BSD-style license that can be
  found in the LICENSE file.

* Author:         dzlua - https://gitee.com/dzlua/
* Email:          505544956@qq.com
* FileName:       base.cc
* Create Time:    2019/01/18 11:34:57
* Description:    test for agile base
\****************************************************/

#include <agile.hpp>

#include "test.h"

void test_min_max();
void test_point();
void test_size();
void test_rect();
void test_color();

int main(int argc, char* argv[]) {
  test_min_max();
  test_point();
  test_size();
  test_rect();
  test_color();
  return 0;
}

void test_min_max() {
  TEST(agile::min(0.f, 0.1f) == 0.f);
  TEST(agile::max(0.f, 0.1f) == 0.1f);

  TEST(agile::min(100, 1) == 1);
  TEST(agile::max(100, 1) == 100);
}

void test_point() {
  agile::Point pt;
  TEST(pt.x() == 0.f);
  TEST(pt.y() == 0.f);

  pt.set_x(10.f);
  TEST(pt.x() == 10.f);

  pt.set_y(10.f);
  TEST(pt.y() == 10.f);

  pt.set(20.f, 30.f);
  TEST(pt.x() == 20.f);
  TEST(pt.y() == 30.f);

  pt.move(10.f, 20.f);
  TEST(pt.x() == 30.f);
  TEST(pt.y() == 50.f);

  pt.move(-20.f, -10.f);
  TEST(pt.x() == 10.f);
  TEST(pt.y() == 40.f);

  agile::Point pt2(10.f, 40.f);
  TEST(pt.x() == 10.f);
  TEST(pt.y() == 40.f);

  TEST(pt == pt2);
  TEST(pt.equal(pt2));

  pt2.move(1.f, -1.f);
  TEST(pt != pt2);
}

void test_size() {
  agile::Size sz;
  TEST(sz.cx() == 0.f);
  TEST(sz.cy() == 0.f);
  TEST(!sz.validate());

  sz.set_cx(10.f);
  TEST(sz.cx() == 10.f);

  sz.set_cy(10.f);
  TEST(sz.cy() == 10.f);

  sz.set(20.f, 30.f);
  TEST(sz.cx() == 20.f);
  TEST(sz.cy() == 30.f);

  sz.scale(10.f, 20.f);
  TEST(sz.cx() == 30.f);
  TEST(sz.cy() == 50.f);

  sz.scale(-20.f, -10.f);
  TEST(sz.cx() == 10.f);
  TEST(sz.cy() == 40.f);

  TEST(sz.validate());

  agile::Size sz2(10.f, 40.f);
  TEST(sz2.cx() == 10.f);
  TEST(sz2.cy() == 40.f);
  TEST(sz.validate());

  TEST(sz == sz2);
  TEST(sz.equal(sz2));

  sz2.scale(1.f, -1.f);
  TEST(sz != sz2);
}

void test_rect() {
  agile::Rect rc;
  TEST(rc.x() == 0.f);
  TEST(rc.y() == 0.f);
  TEST(rc.cx() == 0.f);
  TEST(rc.y() == 0.f);
  TEST(rc.left() == 0.f);
  TEST(rc.top() == 0.f);
  TEST(rc.right() == 0.f);
  TEST(rc.bottom() == 0.f);
  TEST(rc.point() == agile::Point());
  TEST(rc.size() == agile::Size());
  TEST(rc.left_top() == agile::Point());
  TEST(rc.right_bottom() == agile::Point());
  TEST(rc.center() == agile::Point());
  TEST(rc.equal(agile::Point()));
  TEST(rc.equal(agile::Size()));
  TEST(rc.equal(agile::Rect()));
  TEST(!rc.validate());

  agile::Rect rc2(10.f, 10.f, 10.f, 10.f);
  TEST(rc2.x() == 10.f);
  TEST(rc2.y() == 10.f);
  TEST(rc2.cx() == 10.f);
  TEST(rc2.y() == 10.f);
  TEST(rc2.left() == 10.f);
  TEST(rc2.top() == 10.f);
  TEST(rc2.right() == 20.f);
  TEST(rc2.bottom() == 20.f);
  TEST(rc2.point() == agile::Point(10.f, 10.f));
  TEST(rc2.size() == agile::Size(10.f, 10.f));
  TEST(rc2.left_top() == agile::Point(10.f, 10.f));
  TEST(rc2.right_bottom() == agile::Point(20.f, 20.f));
  TEST(rc2.right_top() == agile::Point(20.f, 10.f));
  TEST(rc2.left_bottom() == agile::Point(10.f, 20.f));
  TEST(rc2.center() == agile::Point(15.f, 15.f));
  TEST(rc2.equal(agile::Point(10.f, 10.f)));
  TEST(rc2.equal(agile::Size(10.f, 10.f)));
  TEST(rc2.equal(agile::Rect(10.f, 10.f, 10.f, 10.f)));
  TEST(rc2.validate());

  rc.set_left(10.f);
  rc.set_top(10.f);
  rc.set_right(20.f);
  rc.set_bottom(20.f);
  TEST(rc == rc2);
  TEST(rc.point() == rc2.point());
  TEST(rc.size() == rc2.size());
  TEST(rc.validate());

  rc.set(0.f, 0.f, 0.f, 0.f);
  TEST(rc == agile::Rect());
  TEST(!rc.validate());

  rc.set_left_top(10.f, 10.f);
  rc.set_right_bottom(20.f, 20.f);
  TEST(rc == rc2);
  TEST(rc.validate());

  rc.set_left_top(agile::Point(0.f, 0.f));
  rc.set_right_bottom(agile::Point(0.f, 0.f));
  TEST(rc == agile::Rect());
  TEST(!rc.validate());

  rc.set(10.f, 10.f, 10.f, 10.f);
  TEST(rc == rc2);
  TEST(rc.validate());

  rc.set(agile::Point(0.f, 0.f), agile::Size(0.f, 0.f));
  TEST(rc == agile::Rect());
  TEST(!rc.validate());

  rc.set_point(10.f, 10.f);
  rc.set_size(10.f, 10.f);
  TEST(rc == rc2);
  TEST(rc.validate());

  rc.set_point(agile::Point(0.f, 0.f));
  rc.set_size(agile::Size(0.f, 0.f));
  TEST(rc == agile::Rect());
  TEST(!rc.validate());

  // test center inset
  rc2.set(10.f, 10.f, 10.f, 10.f);
  rc2.set_inset(1.f, 1.f, 1.f, 1.f);
  TEST(rc2 == agile::Rect(11.f, 11.f, 8.f, 8.f));
  TEST(rc2.center() == agile::Point(15.f, 15.f));

  rc2.set(10.f, 10.f, 10.f, 10.f);
  rc2.set_inset(1.f, 2.f, -3.f, -2.f);
  TEST(rc2 == agile::Rect(11.f, 12.f, 12.f, 10.f));
  TEST(rc2.center() == agile::Point(17.f, 17.f));
  rc2.center_scale(10.f, 10.f);
  TEST(rc2.center() == agile::Point(17.f, 17.f));
  TEST(rc2 == agile::Rect(1.f, 2.f, 32.f, 30.f));

  agile::Rect inset;
  inset.set_left_top(1.f, 2.f);
  inset.set_right_bottom(-3.f, -2.f);
  rc2.set(10.f, 10.f, 10.f, 10.f);
  rc2.set_inset(inset);
  TEST(rc2 == agile::Rect(11.f, 12.f, 12.f, 10.f));
  TEST(rc2.center() == agile::Point(17.f, 17.f));
  rc2.center_scale(10.f, 10.f);
  TEST(rc2.center() == agile::Point(17.f, 17.f));
  TEST(rc2 == agile::Rect(1.f, 2.f, 32.f, 30.f));

  // test contains
  rc2.set(10.f, 10.f, 10.f, 10.f);
  TEST(rc2.contains(10.f, 10.f));
  TEST(rc2.contains(20.f, 20.f));
  TEST(!rc2.contains(0.f, 0.f));
  TEST(!rc2.contains(20.f, 21.f));
  TEST(!rc2.contains(100.f, 100.f));
  TEST(rc2.contains(15.f, 15.f));
  TEST(rc2.contains(agile::Point(15.f, 15.f)));

  // test operator
  rc = agile::Point(100.f, 100.f);
  rc = agile::Size(200.f, 200.f);
  TEST(rc == agile::Rect(100.f, 100.f, 200.f, 200.f));
  TEST(rc == agile::Point(100.f, 100.f));
  TEST(rc == agile::Size(200.f, 200.f));
  TEST(rc != agile::Rect(0.f, 100.f, 200.f, 200.f));
  TEST(rc != agile::Point(0.f, 100.f));
  TEST(rc != agile::Size(0.f, 200.f));

  // test intersection inside
  rc.set(0.f, 0.f, 10.f, 10.f);
  rc2.set(20.f, 20.f, 10.f, 10.f);
  TEST(!rc.inside(rc2));
  TEST(!rc2.inside(rc));
  TEST(!rc.has_intersection(rc2));
  rc.set_intersection(rc2);
  TEST(!rc.validate());

  rc.set(0.f, 0.f, 10.f, 10.f);
  rc2.set(5.f, 5.f, 10.f, 10.f);
  TEST(!rc.inside(rc2));
  TEST(!rc2.inside(rc));
  TEST(rc.has_intersection(rc2));
  rc.set_intersection(rc2);
  TEST(rc.validate());
  TEST(rc == agile::Rect(5.f, 5.f, 5.f, 5.f));

  rc.set(0.f, 0.f, 10.f, 10.f);
  rc2.set(5.f, 5.f, 2.f, 2.f);
  TEST(!rc.inside(rc2));
  TEST(rc2.inside(rc));
  TEST(rc.has_intersection(rc2));
  rc.set_intersection(rc2);
  TEST(rc.validate());
  TEST(rc == agile::Rect(5.f, 5.f, 2.f, 2.f));

  // test union
  rc.set(0.f, 0.f, 10.f, 10.f);
  rc2.set(20.f, 20.f, 10.f, 10.f);
  rc.set_union(rc2);
  TEST(rc.validate());
  TEST(rc == agile::Rect(0.f, 0.f, 30.f, 30.f));

  rc.set(0.f, 0.f, 10.f, 10.f);
  rc2.set(5.f, 5.f, 10.f, 10.f);
  rc.set_union(rc2);
  TEST(rc.validate());
  TEST(rc == agile::Rect(0.f, 0.f, 15.f, 15.f));

  rc.set(0.f, 0.f, 10.f, 10.f);
  rc2.set(5.f, 5.f, 2.f, 2.f);
  rc.set_union(rc2);
  TEST(rc.validate());
  TEST(rc == agile::Rect(0.f, 0.f, 10.f, 10.f));
}

void test_color() {
  agile::Color cl;
  TEST(!cl.used());
  TEST(cl.r() == 0.f);
  TEST(cl.g() == 0.f);
  TEST(cl.b() == 0.f);
  TEST(cl.a() == -1.f);

  cl.set(0.5f, 0.6f, 0.7f, 0.8f);
  TEST(cl.used());
  TEST(cl.r() == 0.5f);
  TEST(cl.g() == 0.6f);
  TEST(cl.b() == 0.7f);
  TEST(cl.a() == 0.8f);

  cl.set(0.f, 0.f, 0.f);
  TEST(cl.used());
  TEST(cl.r() == 0.f);
  TEST(cl.g() == 0.f);
  TEST(cl.b() == 0.f);
  TEST(cl.a() == 1.f);

  agile::Color cl1;
  agile::Color cl2(0.f, 0.f, 0.f);
  TEST(cl1 != cl2);
  TEST(cl == cl2);

}